package com.simple.car.loader.server.tools;

import android.content.Context;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;

/**
 * 反射的工具类
 */
public class ReflectionsTool {

    private static Set<String> entryNames;

    private static PathClassLoader classLoader;

    /**
     * 初始化反射工具，它在程序启动时，已经在Program类的子类中被调用过，一般情况下，只要@ScannerPackage注解中的包名是正确的，不需要开发者手动调用此方法。
     *
     * @param ctx         程序的上下文对象
     * @param packageName 被反射工具扫描的最顶层的包名
     */
    public static void init(Context ctx, String packageName) {
        entryNames = new HashSet<>();
        try {
            classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
            DexFile dex = new DexFile(ctx.getPackageResourcePath());
            Enumeration<String> entries = dex.entries();
            while (entries.hasMoreElements()) {
                String entryName = entries.nextElement();
                if (entryName.contains(packageName)) {
                    entryNames.add(entryName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取拥有指定注解的类的Class对象
     *
     * @param cls 指定的注解的Class对象
     *            注意此注解不能被子类继承
     * @return 拥有cls注解的所有类的类对象的Set集合
     */
    public static Set<Class<?>> getClassByAnnotationClass(Class<? extends Annotation> cls) {
        Set<Class<?>> classes = new HashSet<>();
        Class<?> entryClass = null;
        try {
            for (String entryName : entryNames) {
                entryClass = Class.forName(entryName, true, classLoader);
                Annotation annotation = entryClass.getAnnotation(cls);
                if (annotation != null) {
                    classes.add(entryClass);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return classes.isEmpty() ? null : classes;
    }

    /**
     * 返回拥有指定注解的成员变量的Field变量的Set集合
     *
     * @param cls 指定注解的Class对象
     * @return 返回拥有cls注解的所有成员变量的Set集合
     */
    public static Set<Field> getFieldByAnnotation(Class<? extends Annotation> cls) {
        Set<Field> fields = new HashSet<>();
        Class<?> aClass = null;
        try {
            for (String entryName : entryNames) {
                aClass = Class.forName(entryName);
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field field : declaredFields) {
                    Annotation declaredAnnotation = field.getDeclaredAnnotation(cls);
                    if (declaredAnnotation == null) {
                        continue;
                    }
                    fields.add(field);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return fields.isEmpty() ? null : fields;
    }

    /**
     * 获取拥有指定注解的Method对象的Set集合
     *
     * @param cls 指定注解的Class对象
     * @return 拥有cls注解的Method的Set集合
     */
    public static Set<Method> getMethodByAnnotation(Class<? extends Annotation> cls) {
        Set<Method> methods = new HashSet<>();
        Class<?> aClass = null;
        try {
            for (String entryName : entryNames) {
                aClass = Class.forName(entryName, true, classLoader);
                Method[] declaredMethods = aClass.getDeclaredMethods();
                for (Method method : declaredMethods) {
                    Annotation declaredAnnotation = method.getDeclaredAnnotation(cls);
                    if (declaredAnnotation == null) {
                        continue;
                    }
                    methods.add(method);
                }

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return methods.isEmpty() ? null : methods;
    }
}
